package org.datacoder.geocoding

import com.vividsolutions.jts.geom.*
import grails.test.*
import org.datacoder.geocoding.jurisdiction.*

class GeocodingServiceIntegrationTests extends GrailsUnitTestCase {

    GeocodingService geocodingService

    protected void setUp() {
        super.setUp()
    }

    protected void tearDown() {
        super.tearDown()
    }

    void testNonGeocodingQueries() {
        // findByName
        Set<Jurisdiction> protoStPauls = geocodingService.findByName("St. Paul")
        assert protoStPauls.size() >= 1

        // findParentJurisdiction
        Jurisdiction stPaul
        for(protoStPaul in protoStPauls){
            if(protoStPaul.state.name.equals("MN")){
                stPaul = protoStPaul
                break
            }
        }
        Jurisdiction mn = geocodingService.findParentJurisdiction(stPaul)
        assert mn.name.equals("MN")

        // findChildJurisdictions
        Set<Jurisdiction> mnChildren = geocodingService.findChildJurisdictions(mn)
        assert mnChildren.size() > 0

        // findCentroid
        Point centroid = geocodingService.findCentroid(mn)
        assert mn.multiPolygon.contains(centroid)

        // findContainingRectangle
        Envelope envelope = geocodingService.findContainingRectangle(mnChildren)
        assert envelope.contains(centroid.getX(), centroid.getY())

        // findInterveningJurisdictions
        // TODO: Implement me!
    }

    void testGeocodingQueries(){
        long startTime
        long endTime

        Jurisdiction us = geocodingService.findByName("US").iterator().next()
        Jurisdiction mn = geocodingService.findByName("Minnesota").iterator().next()
        Set<Jurisdiction> protoMplss = geocodingService.findByName("Minneapolis")
        Jurisdiction mpls
        for(protoMpls in protoMplss){
            if(protoMpls.state.name.equals("MN")){
                mpls = protoMpls
                break
            }
        }
        Set<Jurisdiction> protoStPauls = geocodingService.findByName("St. Paul")
        Jurisdiction stPaul
        for(protoStPaul in protoStPauls){
            if(protoStPaul.state.name.equals("MN")){
                stPaul = protoStPaul
                break
            }
        }
        Jurisdiction highlandPark = geocodingService.findByName("55116").iterator().next()
        Point highlandVillage = geocodingService.findCentroid(highlandPark)

        // findJurisdictionsNearbyPoint
        startTime = System.nanoTime()
        Set<Jurisdiction> nearbyHighlandVillage = geocodingService.findJurisdictionsNearbyPoint(highlandVillage, 5)
        endTime = System.nanoTime()
        println "findJurisdictionsNearbyPoint: ${(1.0*(endTime - startTime))/Math.pow(10,9)}"
        assert nearbyHighlandVillage.contains(us)
        assert nearbyHighlandVillage.contains(mn)
        assert nearbyHighlandVillage.contains(mpls)
        assert nearbyHighlandVillage.contains(stPaul)
        assert nearbyHighlandVillage.contains(highlandPark)

        // findJurisdictionsContainingJurisdiction
        startTime = System.nanoTime()
        Set<Jurisdiction> containingHighlandPark = geocodingService.findJurisdictionsContainingJurisdiction(highlandPark)
        endTime = System.nanoTime()
        println "findJurisdictionsContainingJurisdiction: ${(1.0*(endTime - startTime))/Math.pow(10,9)}"
        assert containingHighlandPark.contains(us)
        assert containingHighlandPark.contains(mn)
        assert !containingHighlandPark.contains(mpls)
        assert containingHighlandPark.contains(stPaul)
        assert !containingHighlandPark.contains(highlandPark)

        Set<Jurisdiction> containingMN = geocodingService.findJurisdictionsContainingJurisdiction(mn)
        assert containingMN.contains(us)
        assert !containingMN.contains(mn)
        assert !containingMN.contains(mpls)
        assert !containingMN.contains(stPaul)
        assert !containingMN.contains(highlandPark)

        // findJurisdictionsWithinJurisdiction
        startTime = System.nanoTime()
        Set<Jurisdiction> withinHighlandPark = geocodingService.findJurisdictionsWithinJurisdiction(highlandPark)
        endTime = System.nanoTime()
        println "findJurisdictionsWithinJurisdiction: ${(1.0*(endTime - startTime))/Math.pow(10,9)}"
        assert !withinHighlandPark.contains(us)
        assert !withinHighlandPark.contains(mn)
        assert !withinHighlandPark.contains(mpls)
        assert !withinHighlandPark.contains(stPaul)
        assert !withinHighlandPark.contains(highlandPark)

        Set<Jurisdiction> withinMN = geocodingService.findJurisdictionsWithinJurisdiction(mn)
        // assert !withinMN.contains(us) // This assertion will FAIL if only using MN for jurisdictions
        assert !withinMN.contains(mn)
        assert withinMN.contains(mpls)
        assert withinMN.contains(stPaul)
        assert withinMN.contains(highlandPark)

        // findJurisdictionsIntersectingJurisdiction
        startTime = System.nanoTime()
        Set<Jurisdiction> intersectingHighlandPark = geocodingService.findJurisdictionsIntersectingJurisdiction(highlandPark)
        endTime = System.nanoTime()
        println "findJurisdictionsIntersectingJurisdiction: ${(1.0*(endTime - startTime))/Math.pow(10,9)}"
        assert intersectingHighlandPark.contains(us)
        assert intersectingHighlandPark.contains(mn)
        assert !intersectingHighlandPark.contains(mpls)
        assert intersectingHighlandPark.contains(stPaul)
        assert !intersectingHighlandPark.contains(highlandPark)

        Set<Jurisdiction> intersectingMN = geocodingService.findJurisdictionsIntersectingJurisdiction(mn)
        assert intersectingMN.contains(us)
        assert !intersectingMN.contains(mn)
        assert intersectingMN.contains(mpls)
        assert intersectingMN.contains(stPaul)
        assert intersectingMN.contains(highlandPark)

        // findJurisdictionsNearbyJurisdiction
        startTime = System.nanoTime()
        Set<Jurisdiction> nearbyHighlandPark = geocodingService.findJurisdictionsNearbyJurisdiction(highlandPark, 5)
        endTime = System.nanoTime()
        println "findJurisdictionsNearbyJurisdiction: ${(1.0*(endTime - startTime))/Math.pow(10,9)}"
        assert nearbyHighlandPark.contains(us)
        assert nearbyHighlandPark.contains(mn)
        assert nearbyHighlandPark.contains(mpls)
        assert nearbyHighlandPark.contains(stPaul)
        assert !nearbyHighlandPark.contains(highlandPark)

        Set<Jurisdiction> nearbyMN = geocodingService.findJurisdictionsNearbyJurisdiction(mn, 5)
        assert nearbyMN.contains(us)
        assert !nearbyMN.contains(mn)
        assert nearbyMN.contains(mpls)
        assert nearbyMN.contains(stPaul)
        assert nearbyMN.contains(highlandPark)
    }
}
